package com.esteel.settlement.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.esteel.settlement.config.pa.PaTemplate;
import com.esteel.settlement.config.pa.PacketFactory;
import com.esteel.settlement.dao.TbSettPayRepository;
import com.esteel.settlement.entity.TbSettAccount;
import com.esteel.settlement.entity.TbSettFund;
import com.esteel.settlement.entity.TbSettFundChg;
import com.esteel.settlement.entity.TbSettPay;
import com.esteel.settlement.pa.packet.Answer;
import com.esteel.settlement.pa.packet.PaPacket;
import com.esteel.settlement.pa.packet.PlatformOperationPaymentPB1331;
import com.esteel.settlement.pa.packet.RspBP1328;
import com.esteel.settlement.pa.packet.RspBP1331;
import com.esteel.settlement.pa.packet.SubAccountFreezeThawPB1029;
import com.esteel.settlement.pa.packet.SubAccountReviewPayPB1328;
import com.esteel.settlement.pa.service.impl.BankReviewNoticeBP1326Processer;
import com.esteel.settlement.service.SettAccountService;
import com.esteel.settlement.service.SettFundChgService;
import com.esteel.settlement.service.SettFundService;
import com.esteel.settlement.service.SettPayService;
import com.esteel.settlement.vo.PayQueryVo;
import com.esteel.settlement.vo.SettPayVo;
import com.esteel.settlement.vo.TbSettPayVo;

@Service
public class SettPayServiceImpl implements SettPayService {

	@Autowired
	private SettAccountService settAccountService;
	
	@Autowired
	private TbSettPayRepository tbSettPayRepository;
	
	@Autowired
	private SettFundChgService settFundChgService;

	@Autowired
	private SettFundService settFundService;
	
	@Autowired
	private PacketFactory packetFactory;

	@Autowired
	private PaTemplate paTemplate;
	
	@Autowired
	private BankReviewNoticeBP1326Processer bp1326;
	
	@Override
	public TbSettPay save(TbSettPay tbSettPay) {

	
		//生成一个订单 并发送银行方 
		return tbSettPayRepository.save(tbSettPay);
	}

	@Override
	@Transactional
	public Map<String,String> pay(SettPayVo settPay) {
		
		TbSettPay pay = this.findByPaySerialNo(settPay.getPaySerialNo());
		
		
		//付款请求之前无效 可以删除重建
		if (pay!=null){
			if (pay.getStatus()==0||pay.getStatus()==6){
				this.tbSettPayRepository.delete(pay);
			}else{
				Assert.isTrue(false, "付款订单已经存在或者已经完成");
				
			}
			
		}
		
		//判断付款方 out 的账号信息
		TbSettAccount outAccount = settAccountService.findByThirdCustId(settPay.getOutThirdCustId());
		Assert.notNull(outAccount,"付款方账户不存在");

		//判断收款方 in的账户信息
		TbSettAccount inAccount = settAccountService.findByThirdCustId(settPay.getInThirdCustId());
		Assert.notNull(inAccount,"收款方账户不存在");
		
		//付款方账户信息
		TbSettFund outFund = settFundService.findByCustAcctId(outAccount.getId().getCustAcctId());
		Assert.notNull(outFund,"付款方账户信息不存在");
		
		TbSettFund inFund = settFundService.findByCustAcctId(inAccount.getId().getCustAcctId());
		Assert.notNull(inFund,"收款方账户信息不存在");

		
		double tranAmount = settPay.getTranAmount();
		double handFee = settPay.getHandFee();
		
		//判断付款余额是否充足
		Assert.isTrue(outFund.getTotalBalance()>(tranAmount+handFee),"付款账户余额不足");
		

		SubAccountReviewPayPB1328 pb =  packetFactory.getPacket(SubAccountReviewPayPB1328.class);
		
		//存储本地记录
	
		
		TbSettPay tbSettPay = new TbSettPay();
		BeanUtils.copyProperties(settPay, tbSettPay);
		tbSettPay.setCcyCode(pb.getCcyCode());
		tbSettPay.setOutCustAcctId(outAccount.getId().getCustAcctId());
		tbSettPay.setInCustAcctId(inAccount.getId().getCustAcctId());
		tbSettPay.setStatus(0);
		tbSettPay.setTranDate(new Date());
		tbSettPay = this.save(tbSettPay);


		
		pb.setFuncFlag(settPay.getFuncFlag());
		pb.setOutCustAcctId(tbSettPay.getOutCustAcctId());
		pb.setOutThirdCustId(tbSettPay.getOutThirdCustId());
		
		pb.setInCustAcctId(tbSettPay.getInCustAcctId());
		pb.setInThirdCustId(tbSettPay.getInThirdCustId());
		pb.setTranAmount(tbSettPay.getTranAmount());
		pb.setHandFee(tbSettPay.getHandFee());
		pb.setPaySerialNo(tbSettPay.getPaySerialNo());
		pb.setThirdHtId(tbSettPay.getThirdHtId());
		pb.setThirdHtCont(tbSettPay.getThirdHtCont());
		
		pb.setThirdLogNo("1328_"+tbSettPay.getPayId());

//		RspBP1328 rsp = paTemplate.execute(pb, RspBP1328.class);
		
		RspBP1328 rsp = new RspBP1328();
		BeanUtils.copyProperties(pb, rsp);
		rsp.setRspCode("000000");
		rsp.setFrontLogNo(pb.getPaySerialNo());
		
		Assert.isTrue(rsp.isSuccess(),rsp.getRspMsg());
		
		if (rsp.isSuccess()){
			//保存返回结果
			tbSettPay.setStatus(1);
			tbSettPay.setTranDate(rsp.getTransDate());
			tbSettPay = this.save(tbSettPay);
			
			//冻结支付账户的 transAmount+handFee

			outFund.setTotalBalance(outFund.getTotalBalance()-(tranAmount+handFee));
			outFund.setTotalFreezeAmount(outFund.getTotalFreezeAmount()+tranAmount+handFee);
			outFund =settFundService.save(outFund);
			
			//记录资金变动情况

			TbSettFundChg settFundChg = new TbSettFundChg();
			BeanUtils.copyProperties(outFund.getId(), settFundChg);
			BeanUtils.copyProperties(outFund, settFundChg);
			settFundChg.setLinkType(TbSettFundChg.LinkType.PAY);
			settFundChg.setLinkKey(tbSettPay.getPayId());
			settFundChg.setTransDate(rsp.getTransDate());
			//发送交易请求后 交易方资金被冻结
			settFundChg.setChgTotalBalance(-(tranAmount+handFee));
			settFundChg.setChgTotalFreezeAmount(tranAmount+handFee);
			
			settFundChgService.save(settFundChg);

		}
		
		Map<String,String> result = new HashMap<String,String>();
		result.put("rspCode",rsp.getRspCode());
		result.put("rspMsg", rsp.getRspMsg());
		return result;
		
	}

	@Override
	public TbSettPay findByPaySerialNo(String paySerialNo) {
		return tbSettPayRepository.findByPaySerialNo(paySerialNo);
	}
	@Override
	public TbSettPay findOne(long payId) {
		return tbSettPayRepository.findOne(payId);
	}

	@Override
	@Transactional
	public Answer payForce(long payId,int funcFlag) {
		
		TbSettPay settPay = this.findOne(payId);
		Assert.notNull(settPay);
		
		//判断 刚刚发送的数据
		Assert.isTrue(settPay.getStatus()==1);
		
		
		PlatformOperationPaymentPB1331 pb = packetFactory.getPacket(PlatformOperationPaymentPB1331.class);

		pb.setFuncFlag(funcFlag);
		
		pb.setThirdLogNo("1331_" + new Date().getTime());
		BeanUtils.copyProperties(settPay, pb);
		
		//TODO　临时挡板　做为银行端程序错误的处理逻辑
		//RspBP1331 rsp = paTemplate.execute(pb, RspBP1331.class);
		
		RspBP1331 rsp  = new RspBP1331();
		BeanUtils.copyProperties(pb, rsp);
		rsp.setRspCode("000000");
	
		
		
		Assert.isTrue(rsp.getRspCode().equals(PaPacket.SUCCESS),rsp.getRspMsg());
		
		if (rsp.isSuccess()){
			//付款方账户信息
			TbSettFund outFund = settFundService.findByCustAcctId(settPay.getOutCustAcctId());
			Assert.notNull(outFund,"付款方账户信息不存在");
			TbSettFund inFund = settFundService.findByCustAcctId(settPay.getInCustAcctId());
			Assert.notNull(inFund,"收款方账户信息不存在");
			
			settPay.setStatus(4);
			this.save(settPay);
			
			int chgFlag = 0;
			if (funcFlag==PlatformOperationPaymentPB1331.PAYAGENT){
				chgFlag = TbSettFundChg.LinkType.PAYAGENT;
			}
			if (funcFlag==PlatformOperationPaymentPB1331.PAYFORCE){
				chgFlag = TbSettFundChg.LinkType.PAYFORCE;
			}
			//更新支付信息
			bp1326.payComplete(settPay,rsp,chgFlag);
		}
		return rsp;
	}

	@Override
	@Transactional
	public int payment(String orderNo ,Integer quantity) {
		if (quantity==null||quantity==0){
			tbSettPayRepository.paymentNoGoods(orderNo);
			return tbSettPayRepository.logPaymentNoGoods(orderNo);
		}else{
			tbSettPayRepository.payment(orderNo);
			return tbSettPayRepository.logPayment(orderNo);	
		}
		
	}

	@Override
	@Transactional
	public int payFinal(String orderNo) {
		tbSettPayRepository.payFinal(orderNo);
		return tbSettPayRepository.logPayFinal(orderNo);
	}

	@Override
	public Page<TbSettPay> findAll(Pageable page) {
		return tbSettPayRepository.findAll(page);
	}

	@Override
	public void delete(long payId) {
		TbSettPay pay = this.findOne(payId);
		Assert.notNull(pay,"该支付订单不存在");
		Assert.isTrue(pay.getStatus()==0,"支付订单已经生效");
		tbSettPayRepository.delete(payId);
	}

	@Override
	@Transactional
	public Answer unFreezeSettPay(long payId) {
		TbSettPay pay = this.findOne(payId);
		Assert.notNull(pay,"该支付订单不存在");
		Assert.isTrue((pay.getStatus()==2||pay.getStatus()==4)&&pay.getFuncFlag()==1, "该订单金额无法被解冻");
		Answer rsp = settAccountService.saveFreeze(SubAccountFreezeThawPB1029.UNFREEZE, pay.getInCustAcctId(), pay.getInThirdCustId(), pay.getTranAmount());
		if (rsp.isSuccess()){
			pay.setStatus(5);
			this.save(pay);
		}
		return rsp;
	}

	@Override
	@Transactional
	public Answer payCancel(long payId) {
		TbSettPay pay = this.findOne(payId);
		Assert.notNull(pay,"该支付订单不存在");
		
		double tranAmount = pay.getTranAmount();
		double handFee = pay.getHandFee();
		
		SubAccountReviewPayPB1328 pb =  packetFactory.getPacket(SubAccountReviewPayPB1328.class);
		pb.setFuncFlag(SubAccountReviewPayPB1328.PayCancel);
		pb.setOutCustAcctId(pay.getOutCustAcctId());
		pb.setOutThirdCustId(pay.getOutThirdCustId());
		
		pb.setInCustAcctId(pay.getInCustAcctId());
		pb.setInThirdCustId(pay.getInThirdCustId());
		pb.setTranAmount(tranAmount);
		pb.setHandFee(handFee);
		pb.setPaySerialNo(pay.getPaySerialNo());
		pb.setThirdHtId(pay.getThirdHtId());
		pb.setThirdHtCont(pay.getThirdHtCont());
		
		pb.setThirdLogNo("1328_"+pay.getPayId());

		RspBP1328 rsp = paTemplate.execute(pb, RspBP1328.class);
		
		if (rsp.isSuccess()){
			//同步资金变动信息
			TbSettFund outFund = settFundService.findByCustAcctId(pay.getOutCustAcctId());
			outFund.setTotalFreezeAmount(outFund.getTotalFreezeAmount()-tranAmount-handFee);
			outFund.setTotalBalance(outFund.getTotalBalance()+tranAmount+handFee);
			settFundService.save(outFund);
			
			//记录资金变动情况
			TbSettFundChg settFundChg = new TbSettFundChg();
			BeanUtils.copyProperties(outFund.getId(), settFundChg);
			BeanUtils.copyProperties(outFund, settFundChg);
			settFundChg.setLinkType(TbSettFundChg.LinkType.PAYCANCEL);
			settFundChg.setLinkKey(pay.getPayId());
			settFundChg.setTransDate(rsp.getTransDate());
			
			settFundChg.setChgTotalFreezeAmount(-(tranAmount+handFee));
			settFundChg.setChgTotalBalance(tranAmount+handFee);
								
			settFundChgService.save(settFundChg);
			
			pay.setStatus(6);
			this.save(pay);
		}
		
		return rsp;
	}

	@Override
	public Map<String, String> payCancel(String paySerialNo) {
		TbSettPay pay = this.findByPaySerialNo(paySerialNo);
		Assert.notNull(pay,"支付订单不存在");
		Answer rsp = this.payCancel(pay.getPayId());
		
		Map<String,String> result = new HashMap<String,String>();
		result.put("rspCode",rsp.getRspCode());
		result.put("rspMsg", rsp.getRspMsg());
		return result;
	}

	@Override
	public Page<TbSettPayVo> payQuery(final PayQueryVo payQueryVo) {
		
//		Specification<TbSettPay> spec = new Specification<TbSettPay>(){
//
//			@Override
//			public Predicate toPredicate(Root<TbSettPay> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//				
//				List<Predicate> list = new ArrayList<Predicate>();
//
//				//增加收款方条件判断
//				if (!StringUtils.isEmpty(payQueryVo.getInThirdCustAcctId())){
//					list.add(cb.equal(root.get("inThirdCustId").as(String.class), payQueryVo.getInThirdCustAcctId()));
//				}
//				
//				//增加付款方条件判断
//				if (!StringUtils.isEmpty(payQueryVo.getOutThirdCustAcctId())){
//					list.add(cb.equal(root.get("outThirdCustId").as(String.class), payQueryVo.getOutThirdCustAcctId()));
//				}
//				//开始日期
//				if (payQueryVo.getBegin()!=null){
//
//					list.add(cb.greaterThan(root.get("tranDate").as(Date.class), payQueryVo.getBegin()));
//				}
//				//查询结束日期
//				if (payQueryVo.getEnd()!=null){
//					Date end = payQueryVo.getEnd();
//					Calendar cal = Calendar.getInstance();
//					cal.setTime(end);
//					cal.add(Calendar.DATE, 1);
//					list.add(cb.lessThan(root.get("tranDate").as(Date.class), cal.getTime()));
//				}
//				//支付状态
//				if (payQueryVo.getStatus()!=null){
//					list.add(cb.equal(root.get("status").as(Integer.class), payQueryVo.getStatus()));
//				}
//				
//				Predicate[] predicates = new Predicate[list.size()];
//				return query.where(list.toArray(predicates)).orderBy(cb.desc(root.get("payId").as(Long.class))).getRestriction();
//			}
//			
//		};
//		Pageable pageable = new PageRequest(payQueryVo.getPage(),payQueryVo.getSizePerPage());
//		
//		return tbSettPayRepository.findAll(spec, pageable);
		return tbSettPayRepository.payQuery(payQueryVo);
	}

	@Override
	public int payDeposit(String orderNo) {
		tbSettPayRepository.payDeposit(orderNo);
		return tbSettPayRepository.logpayDeposit(orderNo);
	}

}
